/*--------------------------------------------------------------------------------
 * Adaptive Intelligence - Foundation Framework Class Library
 * Version 2.00
 * 
 * String Comparer Class
 *		Represents a string comparison operation that uses specific case and 
 * culture-based or ordinal comparison rules.
 *------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------
 * System Imports
 *------------------------------------------------------------------------------*/
using System;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Collections;

namespace Adaptive.Foundation
{
    /// <summary>
    /// Represents a string comparison operation that uses specific case and 
    /// culture-based or ordinal comparison rules.
    /// </summary>
    /// <remarks>
    /// This interface allows the implementation of customized equality 
    /// comparison for collections. That is, you can create your own 
    /// definition of equality, and specify that this definition be used 
    /// with a collection type that accepts the <b>IEqualityComparer</b> 
    /// interface.
    /// </remarks>
    [ComVisible(false), Serializable]
    public abstract class StringComparer : IComparer, IEqualityComparer
    {
        /*------------------------------------------------------------------------
         * Private Static Member Declarations
         *----------------------------------------------------------------------*/
        #region Private Static Member Declarations
        // Statics
        private static StringComparer _invariantCulture;
        private static StringComparer _invariantCultureIgnoreCase;
        private static StringComparer _ordinal;
        private static StringComparer _ordinalIgnoreCase;
        #endregion

        /*------------------------------------------------------------------------
		 * Constructor / Dispose / Destructor Methods
		 *----------------------------------------------------------------------*/
        #region Constructor / Dispose / Destructor Methods
        /// <summary>
        /// Initializes the static members of the class.
        /// </summary>
        static StringComparer()
        {
            StringComparer._invariantCulture = new CultureAwareComparer(CultureInfo.InvariantCulture, false);
            StringComparer._invariantCultureIgnoreCase = new CultureAwareComparer(CultureInfo.InvariantCulture, true);
            StringComparer._ordinal = new OrdinalComparer(false);
            StringComparer._ordinalIgnoreCase = new OrdinalComparer(true);
        }
        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <remarks>
        /// This is the default constructor.
        /// </remarks>
        protected StringComparer()
        {
        }
        #endregion

        /*------------------------------------------------------------------------
		 * Public Static Properties
		 *----------------------------------------------------------------------*/
        #region Public Static Properties
        /// <summary>
        /// Gets a <see cref="StringComparer"/> object that performs a case-sensitive string comparison 
        /// using the word comparison rules of the current culture. 
        /// </summary>
        /// <value>
        /// A <see cref="StringComparer"/> instance for the current culture.
        /// </value>
        public static StringComparer CurrentCulture
        {
            get
            {
                return new CultureAwareComparer(CultureInfo.CurrentCulture, false);
            }
        }
        /// <summary>
        /// Gets a <see cref="StringComparer"/> object that performs case-insensitive string comparisons 
        /// using the word comparison rules of the current culture.
        /// </summary>
        /// <value>
        /// A <see cref="StringComparer"/> instance for the current culture, ignoring case.
        /// </value>
        public static StringComparer CurrentCultureIgnoreCase
        {
            get
            {
                return new CultureAwareComparer(CultureInfo.CurrentCulture, true);
            }
        }
        /// <summary>
        /// Gets a <see cref="StringComparer"/> object that performs case-insensitive string comparisons 
        /// using the word comparison rules of the invariant culture.
        /// </summary>
        /// <value>
        /// A <see cref="StringComparer"/> instance for the invariant culture.
        /// </value>
        public static StringComparer InvariantCulture
        {
            get
            {
                return StringComparer._invariantCulture;
            }
        }
        /// <summary>
        /// Gets a <see cref="StringComparer"/> object that performs a case-sensitive string 
        /// comparison using the word comparison rules of the invariant culture. 
        /// </summary>
        /// <value>
        /// A <see cref="StringComparer"/> instance for the invariant culture, ignoring case.
        /// </value>
        public static StringComparer InvariantCultureIgnoreCase
        {
            get
            {
                return StringComparer._invariantCultureIgnoreCase;
            }
        }
        /// <summary>
        /// Gets a <see cref="StringComparer"/> object that performs a case-sensitive ordinal 
        /// string comparison.
        /// </summary>
        /// <value>
        /// A <see cref="StringComparer"/> instance for ordinal strings.
        /// </value>
        public static StringComparer Ordinal
        {
            get
            {
                return StringComparer.Ordinal;
            }
        }
        /// <summary>
        /// Gets a <see cref="StringComparer"/> object that performs a case-insensitive ordinal 
        /// string comparison.
        /// </summary>
        /// <value>
        /// A <see cref="StringComparer"/> instance for the ordinal strings, ignoring case.
        /// </value>
        public static StringComparer OrdinalIgnoreCase
        {
            get
            {
                return StringComparer.OrdinalIgnoreCase;
            }
        }
        #endregion

        /*------------------------------------------------------------------------
		 * Public Methods / Functions
		 *----------------------------------------------------------------------*/
        #region Public Methods / Functions
        /// <summary>
        /// When overridden in a derived class, compares two objects and returns an 
        /// indication of their relative sort order.
        /// </summary>
        /// <param name="x">Left-side item to be compared.</param>
        /// <param name="y">Right-side item to be compared.</param>
        /// <returns>
        /// Less than zero if x is less than y or x is null;
        /// Zero if x is equal to y; and 
        /// Greater than zero if x is greater than y or y is null.
        /// </returns>
        public virtual int Compare(object x, object y)
        {
            int returnValue = 0;                //Return value.
            string leftString = string.Empty;   //Left string.
            string rightString = string.Empty;  //Right string.

            //Recast items to type.
            leftString = x as string;
            rightString = y as string;

            if (x == y)
                returnValue = 0;
            
            else if (x == null)
                returnValue = -1;

            else if (y == null)
                returnValue = 1;

            else 
                returnValue = Compare(leftString, rightString);

            return returnValue;
        }
        /// <summary>
        /// When overridden in a derived class, compares two strings and returns an 
        /// indication of their relative sort order.
        /// </summary>
        /// <param name="x">A string to compare to y.</param>
        /// <param name="y">A string to compare to x.</param>
        /// <returns>
        /// Less than zero if x is less than y or x is null;
        /// Zero if x is equal to y; and 
        /// Greater than zero if x is greater than y or y is null.
        /// </returns>
        public abstract int Compare(string x, string y);
        /// <summary>
        /// Creates a StringComparer object that compares strings according to the rules of a specified culture.
        /// </summary>
        /// <param name="culture">
        /// A culture whose linguistic rules are used to perform a string comparison.
        /// </param>
        /// <param name="ignoreCase">
        /// <b>true</b> to specify that comparison operations be case-insensitive; 
        /// <b>false</b> to specify that comparison operations be case-sensitive.
        /// </param>
        /// <returns>
        /// A new StringComparer object that performs string comparisons according to the 
        /// comparison rules used by the culture parameter and the case rule 
        /// specified by the ignoreCase parameter.
        /// </returns>
        public static StringComparer Create(CultureInfo culture, bool ignoreCase)
        {
            if (culture == null)
            {
                throw new ArgumentNullException("culture");
            }
            return new CultureAwareComparer(culture, ignoreCase);
        }
        /// <summary>
        /// When overridden in a derived class, indicates whether two objects are equal.
        /// </summary>
        /// <param name="x">An object to compare to y.</param>
        /// <param name="y">An object to compare to x.</param>
        /// <returns>
        /// <b>true</b> if the items are equal; otherwise, returns <b>false</b>.
        /// </returns>
        public new bool Equals(object x, object y)
        {
            string leftString = string.Empty;   //Left item.
            string rightString = string.Empty;  //Right item.
            bool returnValue = false;           //Return value.

            //Recast objects.
            leftString = x as string;
            rightString = y as string;
            returnValue = (x == y);
            if (!returnValue)
            {

                if ((leftString != null) && (rightString != null))
                    returnValue = Equals(leftString, rightString);
            }
            return returnValue;
        }
        /// <summary>
        /// When overridden in a derived class, indicates whether two strings are equal.
        /// </summary>
        /// <param name="x">A string to compare to y.</param>
        /// <param name="y">A string to compare to x.</param>
        /// <returns>
        /// <b>true</b> if the strings are equal; otherwise, returns <b>false</b>.
        /// </returns>
        public abstract bool Equals(string x, string y);
        /// <summary>
        /// When overridden in a derived class, gets the hash code for the specified object.
        /// </summary>
        /// <param name="obj">An object.</param>
        /// <returns>
        ///  32-bit signed hash code calculated from the value of the obj parameter.
        /// </returns>
        public virtual int GetHashCode(object obj)
        {
            string stringItem = null;
            int returnValue = 0;

            if (obj == null)
            {
                throw new ArgumentNullException("obj");
            }

            stringItem = obj as string;
            if (stringItem != null)
                returnValue = GetHashCode(stringItem);
            else
                returnValue = obj.GetHashCode();

            return returnValue;
        }
        /// <summary>
        /// When overridden in a derived class, gets the hash code for the specified 
        /// string.
        /// </summary>
        /// <param name="obj">A string.</param>
        /// <returns>
        /// 32-bit signed hash code calculated from the value of the obj parameter.
        /// </returns>
        public abstract int GetHashCode(string obj);
        #endregion
    }
}
